// dp[i][j]为从（0，0）移动到（i，j）的最小的和
// dp[i][j] = min(dp[i][j-1], dp[i-1][j]) + grid[i][j]
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        // 动态规划元素比实际元素的索引范围要大1，因为要考虑到边界值
        vector<vector<int>> dp(m + 1, vector<int>(n + 1));
        // 除了（0，0）（0，1）（0，2）设定为0，因为要自然的计算出dp[1][1] = grid[0][0]
        // 其他边界值都要为最大整数，因为要自然计算出dp[1][n]和dp[m][1]的值
        for (int i = 2; i < n + 1; ++i) {
            dp[0][i] = INT_MAX;
        }
        for (int i = 2; i < m + 1; ++i) {
            dp[i][0] = INT_MAX;
        }
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                dp[i + 1][j + 1] = min(dp[i][j + 1], dp[i + 1][j]) + grid[i][j];
            }
        }
        return dp[m][n];
    }
};